package com.lew.jlight.web.shiro.filter;

import com.google.common.collect.Maps;

import com.lew.jlight.core.Response;
import com.lew.jlight.web.entity.Role;
import com.lew.jlight.web.entity.User;
import com.lew.jlight.web.entity.UserRole;
import com.lew.jlight.web.service.LoginService;
import com.lew.jlight.web.service.RoleService;
import com.lew.jlight.web.service.UserRoleService;
import com.lew.jlight.web.util.ServletUtil;
import com.lew.jlight.web.util.UserContextUtil;

import org.apache.shiro.authz.UnauthorizedException;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.StringUtils;
import org.apache.shiro.web.filter.authz.AuthorizationFilter;
import org.apache.shiro.web.util.WebUtils;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;

public class FormLoginFilter extends AuthorizationFilter{

    private RoleService roleService;

    private UserRoleService userRoleService;

    private LoginService loginService;
	
	private String unauthorizedUrl = "/login";

	public String getUnauthorizedUrl() {
		return unauthorizedUrl;
	}

	public void setUnauthorizedUrl(String unauthorizedUrl) {
		this.unauthorizedUrl = unauthorizedUrl;
	}

	@Override
	protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {
        Subject subject = getSubject(request, response);
        if(!subject.isAuthenticated() && subject.isRemembered()){
            Session session = subject.getSession(true);
            if(session.getAttribute("userId") == null){
                String account = subject.getPrincipal().toString();
                User user = loginService.doLogin(account, ServletUtil.getRemoteAddr());
                List<UserRole> userRoleList = userRoleService.getListByUserId(user.getUserId());
                Map<String, String> roleMap = Maps.newHashMap();
                if (userRoleList == null || userRoleList.size() == 0) {
                    throw new UnauthorizedException();
                }
                userRoleList.forEach(userRole -> {
                    Role role = roleService.getByRoleId(userRole.getRoleId());
                    roleMap.put(userRole.getRoleId(), role.getName());
                });
                String roleId = null;
                if (userRoleList.size() > 0) {
                    roleId = userRoleList.get(0).getRoleId();
                }
                UserContextUtil.setAttribute("roleMap", roleMap);
                UserContextUtil.setAttribute("userId", user.getUserId());
                UserContextUtil.setAttribute("account",account);
                UserContextUtil.setAttribute("roleId", roleId);
            }
        }
        return subject.isAuthenticated() || subject.isRemembered();
	}

	@Override
	protected boolean onAccessDenied(ServletRequest request,
			ServletResponse response) throws IOException {

        Subject subject = getSubject(request, response);
        if (subject.getPrincipal() == null) {
        	if(ServletUtil.isAjax(WebUtils.toHttp(request))){
        		Map<String, Object> retMap = new HashMap<>();
    			retMap.put("status", Response.ERROR);
    			retMap.put("msg", "您还没有登录");
        		ServletUtil.write(WebUtils.toHttp(response), retMap);
        	}else{
        		saveRequestAndRedirectToLogin(request, response);
        	}
        } else {
            String unauthorizedUrl = getUnauthorizedUrl();
            if (StringUtils.hasText(unauthorizedUrl)) {
                WebUtils.issueRedirect(request, response, unauthorizedUrl);
            } else {
                WebUtils.toHttp(response).sendError(HttpServletResponse.SC_UNAUTHORIZED);
            }
        }
        return false;
    }


    public void setRoleService(RoleService roleService) {
        this.roleService = roleService;
    }


    public void setUserRoleService(UserRoleService userRoleService) {
        this.userRoleService = userRoleService;
    }

    public void setLoginService(LoginService loginService) {
        this.loginService = loginService;
    }
}
